import os
import re
from bs4 import BeautifulSoup
from pathlib import Path

# 修改基础路径和输出路径的处理
base_path = "cangjie-docs"
doc_path = os.path.join(base_path, "cjnative")

def get_version():
    """从index.html中读取版本信息"""
    try:
        with open(os.path.join(doc_path, "index.html"), 'r', encoding='utf-8') as f:
            soup = BeautifulSoup(f, 'html.parser')
            version_span = soup.find('span', class_='version')
            if version_span:
                return version_span.text
    except (FileNotFoundError, Exception) as e:
        print(f"Warning: Could not read version from index.html: {e}")
    
    return "latest"

cj_libs = [
    {
        "name": "std",
        "pkgs": ["core", "argopt", "ast", "binary", "collection", "collection.concurrent", "console",
                 "convert", "crypto.digest", "crypto.cipher", "database.sql", "deriving", "ffi.python",
                 "format", "fs", "io", "log", "math", "math.numeric", "net", "objectpool", "os",
                 "os.posix", "os.process", "overflow", "random", "reflect", "regex", "runtime", "socket",
                 "sort", "sync", "time", "unicode", "unittest", "unittest.mock", "unittest.mockmacro",
                 "unittest.testmacro", "unittest.common", "unittest.diff", "unittest.prop_test"]
    },
    {
        "name": "compress",
        "pkgs": ["zlib"]
    },
    {
        "name": "crypto",
        "pkgs": ["crypto", "digest", "keys", "x509"]
    },
    {
        "name": "encoding",
        "pkgs": ["base64", "hex", "json", "json.stream", "url", "xml"]
    },
    {
        "name": "fuzz",
        "pkgs": ["fuzz"]
    },
    {
        "name": "log",
        "pkgs": ["log"]
    },
    {
        "name": "logger",
        "pkgs": ["logger"]
    },
    {
        "name": "net",
        "pkgs": ["http", "tls"]
    },
    {
        "name": "serialization",
        "pkgs": ["serialization"]
    }
]

def find_dirs_includes(dir_path: str, *extensions: str) -> list:
    """查找包含指定扩展名的目录"""
    matching_dirs = []
    try:
        for item in os.listdir(dir_path):
            item_path = os.path.join(dir_path, item)
            if os.path.isdir(item_path) and all(ext in item for ext in extensions):
                matching_dirs.append(item_path)
    except FileNotFoundError:
        return []
    return matching_dirs

def generate_cj_doc(intros: list, params: list, return_: str, throws: str, has_indent: bool = False) -> str:
    """生成 Cangjie 文档注释"""
    if not any([intros, params, return_, throws]):
        return None
        
    indent = "\t" if has_indent else ""
    result = [f"{indent}/**"]
    
    if intros:
        result.extend(f"{indent} * {intro}" for intro in intros)
    if params:
        result.extend(f"{indent} * @param {param}" for param in params)
    if return_:
        result.append(f"{indent} * @return {return_}")
    if throws:
        result.append(f"{indent} * @throws {throws}")
        
    result.append(f"{indent}*/")
    return "\n".join(result)

def next_sibling(soup, elem, tag_name: str):
    """查找下一个指定标签的兄弟元素"""
    sibling = elem.find_next_sibling()
    while sibling and sibling.name != tag_name:
        sibling = sibling.find_next_sibling()
    return sibling

def main():
    # 获取版本号
    version = get_version()
    # 修改输出目录，包含版本号
    global target_dir
    target_dir = os.path.join("cangjie_libs", version)
    
    # 创建目标目录
    Path(target_dir).mkdir(parents=True, exist_ok=True)
    
    for lib in cj_libs:
        for pkg in lib["pkgs"]:
            lib_path = None
            pkg_name = pkg.replace(".", "_")
            
            # 处理特殊情况
            if lib["name"] == "std":
                if pkg.startswith("crypto"):
                    crypto_parts = pkg.split(".")
                    search_path = os.path.join(doc_path, "libs", lib["name"], 
                                             crypto_parts[0], crypto_parts[1])
                    lib_path = find_dirs_includes(search_path, "api")[0] if find_dirs_includes(search_path, "api") else None
                elif "mockmacro" in pkg:
                    search_path = os.path.join(doc_path, "libs", lib["name"], "unittest_testmacro")
                    lib_path = find_dirs_includes(search_path, "api", "mockmacro")[0] if find_dirs_includes(search_path, "api", "mockmacro") else None
                elif "testmacro" in pkg:
                    search_path = os.path.join(doc_path, "libs", lib["name"], "unittest_testmacro")
                    lib_path = find_dirs_includes(search_path, "api", "testmacro")[0] if find_dirs_includes(search_path, "api", "testmacro") else None
            
            # 默认路径查找
            if not lib_path:
                search_path = os.path.join(doc_path, "libs", lib["name"], pkg_name)
                lib_path = find_dirs_includes(search_path, "api")[0] if find_dirs_includes(search_path, "api") else None
            
            if not lib_path:
                print(f"{lib['name']}.{pkg} no api found.")
                continue
                
            print(f"{lib['name']}.{pkg} processing...")
            content = [f"package {lib['name']}.{pkg}\n"]
            
            # 处理每个HTML文件
            for file in os.listdir(lib_path):
                type_match = re.search(r"([0-9a-zA-Z]+)(?=\.html)", file)
                if not type_match:
                    continue
                    
                type_name = type_match.group(0)
                content.append(f"// ---------------------------")
                content.append(f"// -----{type_name}")
                content.append(f"// ---------------------------")
                
                with open(os.path.join(lib_path, file), 'r', encoding='utf-8') as f:
                    soup = BeautifulSoup(f, 'html.parser')
                main_content = soup.find(id="content")
                
                if "macro" in type_name:
                    # 处理宏定义
                    for h2 in main_content.find_all("h2"):
                        name = h2.find("code")
                        if not name:
                            continue
                        name = name.text
                        intro_p = next_sibling(soup, h2, "p")
                        intro = intro_p.text.strip() if intro_p else ""
                        
                        if intro.startswith("功能"):
                            doc = generate_cj_doc([intro[3:].strip()], [], None, None, False)
                            if doc:
                                content.append(doc)
                        if name:
                            content.append(f"public macro {name}(input: Tokens): Tokens\n")
                else:
                    # 处理普通定义
                    for elem in main_content.find_all(["h2", lambda tag: tag.get('id', '').startswith('extend') and tag.get('id') != 'extend']):
                        process_definition(elem, soup, content)
                
                content.append("\n")
            
            # 写入文件
            out_dir = Path(target_dir) / lib["name"]
            out_dir.mkdir(parents=True, exist_ok=True)
            out_file = out_dir / f"{pkg}.cjd"
            
            with open(out_file, 'w', encoding='utf-8') as f:
                f.write('\n'.join(content))
                
            print(f"{lib['name']}.{pkg} done.")

def process_definition(elem, soup, content):
    """处理定义部分"""
    comments = []
    decls = []
    top_decl_node = next_sibling(soup, elem, "pre")
    if not top_decl_node:
        return
        
    name_code = top_decl_node.find("code")
    if not name_code:
        return
        
    name = name_code.text + "{"
    decls.append(name[:name.find("{")].replace("  ", " ").strip())
    
    comment = {
        "intros": [],
        "params": [],
        "return": "",
        "throws": ""
    }
    
    is_top_decl = True
    
    def push_comment():
        nonlocal is_top_decl
        doc = generate_cj_doc(
            comment["intros"],
            comment["params"],
            comment["return"],
            comment["throws"],
            not is_top_decl
        )
        comments.append(doc)
        is_top_decl = False
        comment.update({
            "intros": [],
            "params": [],
            "return": "",
            "throws": ""
        })
    
    # 处理后续元素
    current = top_decl_node.find_next_sibling()
    while current and current.name not in ["h2"] and not (current.get('id', '').startswith('extend') and current.get('id') != 'extend'):
        if current.name == "pre":
            push_comment()
            code = current.find("code", class_="language-cangjie")
            if code:
                decl = code.text.replace("\n", "").replace("\r", "").replace("\t", "").replace("  ", " ").strip()
                if decl:
                    decls.append(decl)
        elif current.name == "p":
            text = current.text.replace("  ", " ").strip()
            if text.startswith("功能"):
                comment["intros"].append(text[3:].strip())
            elif text.startswith("参数"):
                ul = current.find_next_sibling("ul")
                if ul:
                    for li in ul.find_all("li"):
                        comment["params"].append(li.text.replace("  ", " ").strip())
            elif text.startswith("返回值"):
                ul = current.find_next_sibling("ul")
                if ul and ul.find("li"):
                    comment["return"] = ul.find("li").text.replace("  ", " ").strip()
            elif text.startswith("异常"):
                ul = current.find_next_sibling("ul")
                if ul and ul.find("li"):
                    comment["throws"] = ul.find("li").text.replace("  ", " ").strip()
            else:
                comment["intros"].append(text)
        current = current.find_next_sibling()
    
    push_comment()
    
    # 生成最终内容
    if name and decls[0] not in ''.join(content):
        if comments[0]:
            content.append(f"{comments[0]}")
        content.append(decls[0])
        
        if len(decls) > 1:
            content.append(" {")
            for i, decl in enumerate(decls[1:], 1):
                if comments[i]:
                    content.append(comments[i])
                if "enum" in name and ":" not in decl:
                    content.append(f"\t| {decl}")
                else:
                    content.append(f"\t{decl}")
                if i != len(decls) - 1:
                    content.append("")
            content.append("}")
        elif any(keyword in name for keyword in ["class", "struct", "interface", "extend"]):
            content.append(" {}")
        content.append("\n")

if __name__ == "__main__":
    main()
    print("\nThe Cangjie standard library definitions generated by the script are not entirely accurate.")
    print("Please use Git to compare them with the original library files and manually verify.")
    print("Specifically, unittest-related library files should be carefully reviewed.") 